using System;
using System.Collections.Generic;
using System.Linq;

namespace MT5Trade.Models
{
    /// <summary>
    /// K-means聚类算法实现
    /// 用于GARCH模型的波动率聚类检测
    /// 符合算法实现规则：不使用Random类，使用确定性算法
    /// </summary>
    public class KMeansClustering
    {
        #region 常量定义

        /// <summary>最大迭代次数</summary>
        private const int MAX_ITERATIONS = 100;

        /// <summary>收敛判断阈值</summary>
        private const double CONVERGENCE_TOLERANCE = 1e-6;

        #endregion

        #region 私有字段

        private readonly int _k;
        private readonly IRandomProvider _randomProvider;
        private double[] _centroids;
        private double _lastInertia;

        #endregion

        #region 构造函数

        /// <summary>
        /// 初始化K-means聚类器
        /// </summary>
        /// <param name="k">聚类数量</param>
        /// <param name="randomProvider">随机数提供器（可选）</param>
        public KMeansClustering(int k, IRandomProvider randomProvider = null)
        {
            if (k <= 0)
            {
                throw new ArgumentException("聚类数量必须大于0", nameof(k));
            }

            _k = k;
            _randomProvider = randomProvider ?? DeterministicRandomProvider.CreateForOptimization("kmeans");
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 执行K-means聚类
        /// 数学原理：最小化组内平方和 Σ Σ ||x_i - μ_k||²
        /// </summary>
        /// <param name="data">一维数据点</param>
        /// <returns>每个数据点的聚类标签</returns>
        public int[] Cluster(double[] data)
        {
            if (data == null || data.Length == 0)
            {
                throw new ArgumentException("数据不能为空", nameof(data));
            }

            if (data.Length < _k)
            {
                throw new ArgumentException($"数据点数量({data.Length})必须不少于聚类数量({_k})", nameof(data));
            }

            // 初始化聚类中心（使用K-means++方法）
            InitializeCentroids(data);

            int[] labels = new int[data.Length];
            int[] oldLabels = new int[data.Length];
            int iteration = 0;
            bool converged = false;

            while (iteration < MAX_ITERATIONS && !converged)
            {
                // 保存旧标签
                Array.Copy(labels, oldLabels, labels.Length);

                // E步：分配数据点到最近的聚类中心
                AssignClusters(data, labels);

                // M步：更新聚类中心
                UpdateCentroids(data, labels);

                // 检查收敛
                converged = CheckConvergence(labels, oldLabels);
                iteration++;
            }

            // 计算最终的惯性值
            _lastInertia = CalculateInertia(data, labels);

            return labels;
        }

        /// <summary>
        /// 获取聚类中心
        /// </summary>
        /// <returns>聚类中心数组</returns>
        public double[] GetCentroids()
        {
            return (double[])_centroids?.Clone();
        }

        /// <summary>
        /// 计算聚类质量指标（组内平方和）
        /// </summary>
        /// <param name="data">数据点</param>
        /// <param name="labels">聚类标签</param>
        /// <returns>组内平方和</returns>
        public double CalculateInertia(double[] data, int[] labels)
        {
            double inertia = 0;
            for (int i = 0; i < data.Length; i++)
            {
                double diff = data[i] - _centroids[labels[i]];
                inertia += diff * diff;
            }
            return inertia;
        }

        /// <summary>
        /// 获取最后一次聚类的惯性值
        /// </summary>
        /// <returns>惯性值（组内平方和）</returns>
        public double GetInertia()
        {
            return _lastInertia;
        }

        /// <summary>
        /// 兼容性方法：对多维数据点进行聚类
        /// </summary>
        /// <param name="dataPoints">多维数据点列表</param>
        /// <param name="k">聚类数量（忽略，使用构造函数中的k）</param>
        /// <param name="maxIterations">最大迭代次数（忽略）</param>
        /// <returns>聚类分配列表</returns>
        public List<int> Cluster(List<double[]> dataPoints, int k, int maxIterations)
        {
            // 将多维数据转换为一维数组（简化处理）
            // 这里我们取每个数据点的第一个维度作为聚类依据
            double[] data = dataPoints.Select(p => p.Length > 0 ? p[0] : 0).ToArray();

            // 执行聚类
            int[] assignments = Cluster(data);

            // 转换为List<int>返回
            return assignments.ToList();
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 初始化聚类中心（K-means++方法）
        /// 算法：选择相距较远的点作为初始中心，提高收敛速度
        /// </summary>
        private void InitializeCentroids(double[] data)
        {
            _centroids = new double[_k];
            var selectedIndices = new HashSet<int>();

            // 选择第一个中心（确定性选择：数据的中位数附近）
            var sortedData = data.OrderBy(x => x).ToArray();
            int firstIndex = sortedData.Length / 2;
            _centroids[0] = sortedData[firstIndex];
            
            // 找到原始数据中对应的索引
            for (int i = 0; i < data.Length; i++)
            {
                if (Math.Abs(data[i] - _centroids[0]) < 1e-10)
                {
                    selectedIndices.Add(i);
                    break;
                }
            }

            // 选择剩余的中心（基于距离的确定性选择）
            for (int k = 1; k < _k; k++)
            {
                double[] distances = new double[data.Length];
                double totalDistance = 0;

                // 计算每个点到最近中心的距离
                for (int i = 0; i < data.Length; i++)
                {
                    if (selectedIndices.Contains(i))
                    {
                        distances[i] = 0;
                        continue;
                    }

                    double minDist = double.MaxValue;
                    for (int j = 0; j < k; j++)
                    {
                        double dist = Math.Abs(data[i] - _centroids[j]);
                        minDist = Math.Min(minDist, dist);
                    }
                    distances[i] = minDist * minDist; // 使用距离的平方
                    totalDistance += distances[i];
                }

                // 选择距离最大的点作为下一个中心（确定性）
                double maxDist = 0;
                int selectedIdx = -1;
                for (int i = 0; i < distances.Length; i++)
                {
                    if (distances[i] > maxDist)
                    {
                        maxDist = distances[i];
                        selectedIdx = i;
                    }
                }

                if (selectedIdx >= 0)
                {
                    _centroids[k] = data[selectedIdx];
                    selectedIndices.Add(selectedIdx);
                }
                else
                {
                    // 如果没有找到合适的点，使用均匀分布
                    _centroids[k] = sortedData[(k * sortedData.Length) / _k];
                }
            }
        }

        /// <summary>
        /// 分配数据点到最近的聚类中心
        /// </summary>
        private void AssignClusters(double[] data, int[] labels)
        {
            for (int i = 0; i < data.Length; i++)
            {
                double minDist = double.MaxValue;
                int bestCluster = 0;

                for (int k = 0; k < _k; k++)
                {
                    double dist = Math.Abs(data[i] - _centroids[k]);
                    if (dist < minDist)
                    {
                        minDist = dist;
                        bestCluster = k;
                    }
                }

                labels[i] = bestCluster;
            }
        }

        /// <summary>
        /// 更新聚类中心为各聚类的均值
        /// </summary>
        private void UpdateCentroids(double[] data, int[] labels)
        {
            double[] newCentroids = new double[_k];
            int[] counts = new int[_k];

            // 计算每个聚类的总和和计数
            for (int i = 0; i < data.Length; i++)
            {
                newCentroids[labels[i]] += data[i];
                counts[labels[i]]++;
            }

            // 计算均值
            for (int k = 0; k < _k; k++)
            {
                if (counts[k] > 0)
                {
                    _centroids[k] = newCentroids[k] / counts[k];
                }
                // 如果某个聚类没有数据点，保持原中心不变
            }
        }

        /// <summary>
        /// 检查聚类是否收敛
        /// </summary>
        private bool CheckConvergence(int[] labels, int[] oldLabels)
        {
            // 检查标签是否改变
            for (int i = 0; i < labels.Length; i++)
            {
                if (labels[i] != oldLabels[i])
                {
                    return false;
                }
            }
            return true;
        }

        #endregion
    }

    /// <summary>
    /// 聚类结果统计
    /// </summary>
    public class ClusteringStatistics
    {
        /// <summary>聚类标签</summary>
        public int[] Labels { get; set; }

        /// <summary>聚类中心</summary>
        public double[] Centroids { get; set; }

        /// <summary>每个聚类的大小</summary>
        public int[] ClusterSizes { get; set; }

        /// <summary>组内平方和</summary>
        public double Inertia { get; set; }

        /// <summary>轮廓系数（聚类质量度量）</summary>
        public double SilhouetteScore { get; set; }

        /// <summary>
        /// 获取聚类摘要
        /// </summary>
        public string GetSummary()
        {
            return $"聚类数量: {Centroids?.Length ?? 0}\n" +
                   $"组内平方和: {Inertia:F6}\n" +
                   $"轮廓系数: {SilhouetteScore:F4}\n" +
                   $"聚类大小分布: [{string.Join(", ", ClusterSizes ?? new int[0])}]";
        }
    }
}